#ifndef FloatingDockContainerH
#define FloatingDockContainerH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   FloatingDockContainer.h
/// \author Uwe Kindler
/// \date   01.03.2017
/// \brief  Declaration of CFloatingDockContainer class
//============================================================================

//============================================================================
//                                   INCLUDES
//============================================================================
#include "ads_globals.h"

#include <QRubberBand>

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include <QDockWidget>
#define tFloatingWidgetBase QDockWidget
#else
#include <QWidget>
#define tFloatingWidgetBase QWidget
#endif

class CDockingStateReader;

namespace ads
{
struct FloatingDockContainerPrivate;
class CDockManager;
struct DockManagerPrivate;
class CDockAreaWidget;
class CDockContainerWidget;
class CDockWidget;
class CDockManager;
class CDockAreaTabBar;
class CDockWidgetTab;
struct DockWidgetTabPrivate;
class CDockAreaTitleBar;
struct DockAreaTitleBarPrivate;
class CFloatingWidgetTitleBar;
class CDockingStateReader;

/**
 * 纯虚拟接口，用于浮动小部件。
 * 此接口用于不透明和非透明的解锁。如果使用不透明解锁，则会创建一个真实的CFloatingDockContainer小部件
 */
class ADS_EXPORT IFloatingWidget
{
public:
    virtual ~IFloatingWidget() = default;

    /**
     * 开始浮动。
     * 通常应该从鼠标按下事件处理程序调用此函数
     * @param DragStartMousePos 拖动开始的鼠标位置
     * @param Size 尺寸
     * @param DragState 拖动状态
     * @param MouseEventHandler 鼠标事件处理程序
     */
    virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
        eDragState DragState, QWidget* MouseEventHandler) = 0;

	/**
 * 当鼠标移动事件发生时，将小部件移动到相对于调用startFloating()时给定的位置的新位置。
 * 此函数应该从鼠标移动事件处理程序中调用，以在鼠标移动事件中移动浮动小部件。
 */
virtual void moveFloating() = 0;

/**
 * 如果鼠标释放，则告诉小部件完成拖动。
 * 此函数应该从鼠标释放事件处理程序中调用，以完成拖动。
 */
virtual void finishDragging() = 0;
};


/**
 * 这个类实现了一个浮动小部件，它是一个可以接受停靠的停靠容器，类似于主窗口，并且可以停靠到另一个停靠容器中。
 * 每个浮动窗口都是一个FloatingDockContainer的实例。
 */
class ADS_EXPORT CFloatingDockContainer : public tFloatingWidgetBase, public IFloatingWidget
{
    Q_OBJECT

private:
    FloatingDockContainerPrivate* d; ///< 私有数据（pimpl）

    // 友元类和结构体
    friend struct FloatingDockContainerPrivate;
    friend class CDockManager;
    friend struct DockManagerPrivate;
    friend class CDockAreaTabBar;
    friend struct DockWidgetTabPrivate;
    friend class CDockWidgetTab;
    friend class CDockAreaTitleBar;
    friend struct DockAreaTitleBarPrivate;
    friend class CDockWidget;
    friend class CDockAreaWidget;
    friend class CFloatingWidgetTitleBar;

private Q_SLOTS:
    // 槽函数，处理停靠区域的添加或移除
    void onDockAreasAddedOrRemoved();

    // 槽函数，处理当前停靠区域的改变
    void onDockAreaCurrentChanged(int Index);

protected:
    /**
     * 在给定的全局位置开始浮动。
     * 使用moveToGlobalPos()将小部件移动到根据Pos参数给定的起始位置的新位置
     */
    virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
                               eDragState DragState, QWidget* MouseEventHandler) override;

    /**
     * 调用该函数开始拖动浮动小部件
     */
    void startDragging(const QPoint& DragStartMousePos, const QSize& Size,
                       QWidget* MouseEventHandler)
    {
        startFloating(DragStartMousePos, Size, DraggingFloatingWidget, MouseEventHandler);
    }

    /**
     * 调用该函数如果你明确要标记拖动已经完成
     */
    virtual void finishDragging() override;

    /**
     * 调用该函数如果你只想初始化浮动小部件的位置和大小
     */
    void initFloatingGeometry(const QPoint& DragStartMousePos, const QSize& Size)
    {
        startFloating(DragStartMousePos, Size, DraggingInactive, nullptr);
    }

    /**
     * 将小部件移动到相对于调用startFloating()时给定的位置的新位置
     */
    void moveFloating() override;

    /**
     * 从给定的流中恢复状态。
     * 如果Testing为true，则函数只解析给定流中的数据，但不恢复任何内容。您可以在开始恢复状态之前使用此检查来检查错误的文件
     */
    bool restoreState(CDockingStateReader& Stream, bool Testing);

    /**
     * 调用该函数更新窗口标题
     */
    void updateWindowTitle();

protected:
    // 重新实现QWidget
    virtual void changeEvent(QEvent *event) override;
    virtual void closeEvent(QCloseEvent *event) override;
    virtual void hideEvent(QHideEvent *event) override;
    virtual void showEvent(QShowEvent *event) override;

#ifdef Q_OS_MACOS
    // 重新实现QWidget
    virtual bool event(QEvent *e) override;
    virtual void moveEvent(QMoveEvent *event) override;
#elif defined(Q_OS_UNIX)
    // 重新实现QWidget
    virtual void moveEvent(QMoveEvent *event) override;
    virtual void resizeEvent(QResizeEvent *event) override;
    virtual bool event(QEvent *e) override;
#endif

#ifdef Q_OS_WIN
    /**
     * 用于处理Windows上的WM_MOVING消息的本地事件过滤器
     */
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
    virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
#else
    virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
#endif
#endif

public:
    using Super = tFloatingWidgetBase;

    /**
     * 创建空的浮动窗口 - 用于恢复状态
     */
    CFloatingDockContainer(CDockManager* DockManager);

    /**
     * 创建具有给定停靠区域的浮动窗口
     */
    CFloatingDockContainer(CDockAreaWidget* DockArea);

    /**
     * 创建具有给定停靠窗口的浮动窗口
     */
    CFloatingDockContainer(CDockWidget* DockWidget);

    /**
     * 虚拟析构函数
     */
    virtual ~CFloatingDockContainer();

    /**
     * 访问内部停靠容器的函数
     */
    CDockContainerWidget* dockContainer() const;

    /**
     * 如果可以关闭，则此函数返回true。
     * 如果所有停靠区域中的所有停靠窗口都可以关闭，则可以关闭。
     */
    bool isClosable() const;

    /**
     * 如果此浮动窗口仅具有单个可见停靠窗口，则此函数返回true。
     * 单个停靠窗口是真正的顶级浮动窗口，因为没有其他窗口停靠。
     */
    bool hasTopLevelDockWidget() const;

    /**
     * 此函数返回第一个停靠区域中的第一个停靠窗口。
     * 如果函数hasSingleDockWidget（）返回true，则此函数返回此单个停靠窗口。
     */
    CDockWidget* topLevelDockWidget() const;

    /**
     * 此函数返回此浮动窗口中的所有停靠窗口的列表。
     * 这是一个简单的便利函数，只需调用内部容器小部件的dockWidgets（）函数即可。
     */
    QList<CDockWidget*> dockWidgets() const;

    /**
     * 此函数立即隐藏浮动栏并稍后删除它。
     */
    void hideAndDeleteLater();

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    /**
     * 响应FloatingWidgetTitleBar::maximizeRequest()的函数
     * 最大化或还原容器大小。
     */
    void onMaximizeRequest();
    
    /**
     * 还原（取消最大化）窗口。
     * fixGeometry参数修复了QT中的一个“bug”，即在调用showNormal后立即移动窗口时，几何形状没有正确设置。
     * 在立即还原后移动窗口时，将此参数设置为true。
     */
    void showNormal(bool fixGeometry = false);
    
    /**
     * 最大化窗口。
     */
    void showMaximized();
    
    /**
     * 返回窗口当前是否最大化。
     */
    bool isMaximized() const;
    
    /**
     * 修补的show函数，防止窗口出现在任务栏中。
     */
    void show();
    
    /**
     * 如果浮动小部件具有本机标题栏，则返回true；如果浮动小部件具有基于QWidget的标题栏，则返回false。
     */
    bool hasNativeTitleBar();
#endif
}; // class FloatingDockContainer
}
 // namespace ads
//-----------------------------------------------------------------------------
#endif // FloatingDockContainerH
